//
//$Id: min_com.h 680 2011-03-12 17:01:40Z andrew.tsyganov $
#pragma once

#include "types.h"
#include "sets.h"
#include "fa.h"
#include "grids.h"

const std::string kCOMXmlNode             = "min_com";
const std::string kCOMXmlSolverNode       = "solver";
const std::string kCOMXmlVerbosityNode    = "verbosity";
const std::string kCOMXmlFindAllNode      = "find_all";
const std::string kCOMXmlMinCoverSizeNode = "min_cover_size";
const std::string kCOMXmlMaxCoverSizeNode = "max_cover_size";
const std::string kCOMXmlGAXmlNode        = "ga_xml";
const std::string kCOMXmlSAXmlNode        = "sa_xml";
const std::string kCOMXmlPrefixesNode     = "prefixes";
const std::string kCOMXmlSymbolsNode      = "symbols";
const std::string kCOMXmlANode            = "a";
const std::string kCOMXmlDANode           = "da";
const std::string kCOMXmlMDANode          = "mda";
const std::string kCOMXmlDRMDANode        = "drmda";
const std::string kCOMXmlMDRMDANode       = "mdrmda";
const std::string kCOMXmlCOMNode          = "com";
const std::string kCOMXmlBANode           = "ba";

const std::string kCOMStateExact = "state_exact";
const std::string kCOMStateGA    = "state_ga";
const std::string kCOMStateSA    = "state_sa";

const std::string kCOMSAXml      = "sa.xml";
const std::string kCOMGAXml      = "ga.xml";

const std::string kCOMSymbolsPfx = "a";
const std::string kCOMAPfx       = "";
const std::string kCOMDAPfx      = "p";
const std::string kCOMMDAPfx     = "x";
const std::string kCOMDRMDAPfx   = "q";
const std::string kCOMMDRMDAPfx  = "u";
const std::string kCOMCOMPfx     = "c";
const std::string kCOMBAPfx      = "b";

namespace com
{
class COM_Parameters
{
public:
    std::string solver_; 
    int verbosity_;
    bool find_all_;

    u_t min_cover_size_;
    u_t max_cover_size_;

    std::string sa_xml_; 
    std::string ga_xml_; 

	std::string symbols_pfx_;   
    std::string a_pfx_;   
    std::string da_pfx_;   
    std::string mda_pfx_;  
    std::string drmda_pfx_;  
    std::string mdrmda_pfx_;  
    std::string com_pfx_;  
    std::string ba_pfx_; 

    COM_Parameters() { init_Default(); }

	void init_Default();
	void print_TXT(std::ostream& os) const;
	bool load_XML(std::string file);
};

enum D_COM_Stat {DA_TIME = 0, 
                 MDA_TIME = 1, 
				 RMDA_TIME = 2, 
				 DRMDA_TIME = 3, 
				 MDRMDA_TIME = 4, 
				 COM_TIME = 5, 
				 BA_TIME = 6, 
				 REL_TIME = 7, 
				 GRIDS_TIME = 8, 
				 PREPARE_TIME = 9, 
				 SA_TIME = 10, 
				 GA_TIME = 11, 
				 COVERS_TIME = 12, 
				 TOTAL_TIME = 13,
                 REL_ONES_DENSITY = 14,
                 BA_TRANS_DENSITY = 15,
				 COM_TRANS_DENSITY = 16};

const u_t kDCOMStatNum = 17;

enum U_COM_Stat {A_STATES = 0, 
                 DA_STATES = 1, 
				 MDA_STATES = 2, 
				 DRMDA_STATES = 3, 
				 MDRMDA_STATES = 4, 
				 REL_ROWS = 5, 
				 REL_COLUMNS = 6, 
				 REL_SIZE = 7,
				 REL_ONES_COUNT = 8, 
				 GRIDS_COUNT = 9,
				 FIXED_COUNT = 10,
				 MIN_COVER_SIZE = 11,
				 MAX_COVER_SIZE = 12,
				 MIN_COUNT = 13,
				 MIN_STATES = 14,
				 BA_IN_STATES = 15, 
				 BA_FIN_STATES = 16, 				
				 BA_TRANSITIONS = 17,
				 COM_IN_STATES = 18,
				 COM_FIN_STATES = 19, 
				 COM_TRANSITIONS = 20};

const u_t kUCOMStatNum = 21;

enum B_COM_Stat {ILLEG_MIN_COVERS = 0,
                 MIN_MDA = 1,
                 UNMINIMIZED = 2};

const u_t kBCOMStatNum = 3;

class COM_Statistics
{
public:
    std::vector<double> iterations_time_;
	std::vector<double> d_;
	std::vector<u_t>    u_;
	std::vector<bool>   b_;

	COM_Statistics();
    void reset();
};

class Min_COM
{
    // a_              - input automaton A
    // da_             - determinized A (det(A))
    // mda_            - minimalized det(A) (min(det(A)))
    // rmda_           - reversed min(det(A)) (rev(min(det(A))))
    // drmda_          - determinized rev(min(det(A))) (det(rev(min(det(A)))))
    // mdrmda_         - minimilized det(rev(min(det(A)))) (min(det(rev(min(det(A))))))
    // com_            - COM automaton for A (com(A))
    // ba_             - BA automaton for A (ba(A))
    // vs_a_           - subsets of states of A
    // vs_da_          - subsets of states of det(A)
    // vs_rmda_        - subsets of states of rev(min(det(A)))
    // vs_drmda_       - subsets of states of det(rev(min(det(A))))
	// nes_num_da_     - number of nonempty subsets in vs_da_
	// nes_num_drmda_  - number of nonempty subsets in vs_drmda_
    // rel_            - #-table
    // grids_          - set of grids
    // v_min_          - vector of minimal automata found
    // n_threads_      - number of threads for OpenMP version or processes for MPI version
    // stat_           - statistics
public:
    COM_Statistics  stat_;
    std::vector<FA> v_min_;
	
	FA const& get_BA() const { return ba_; };
	FA const& get_COM() const { return com_; };

    void output_FA(std::ostream& os, FA const& a, Labels_Prefix const& lp, double const time = -1) const;
    void output_DFA(std::ostream& os, FA const& da, FA const& a, std::vector<Subset> const& vs_a, Labels_Prefix const& lp_da, Labels_Prefix const& lp_a, double const time = -1) const;
    void output_BA(std::ostream& os, double const time = -1) const;
    void output_subCOM(std::ostream& os, FA const& scom, Subset const& s, double const time = -1) const;
    void output_Grids(std::ostream& os) const;
    void output_Rel(std::ostream& os) const;
    void output_Cover(std::ostream& os, Subset const& s) const;
    void output_CM(std::ostream& os, Subset_Matrix const& cm) const;

protected:
    FA const& a_; 
    FA da_, mda_, rmda_, drmda_, mdrmda_, ba_, com_;
    std::vector<Subset> vs_a_, vs_da_, vs_rmda_, vs_drmda_;
    u_t nes_num_da_, nes_num_drmda_;
	Bool_Matrix rel_;
 	Subset_Matrix cm_;

	std::vector<States_Pair> vsp_ba_;
	std::vector<Simple_Loop> vsl_ba_;

    std::vector<Grid> grids_;

    COM_Parameters const& param_;

    Min_COM(FA const& a, COM_Parameters const& p) : a_(a), param_(p)
    {}
    
    void clear();

    void build_DA();
    void build_MDA();
    void build_RMDA();
    void build_DRMDA();
    void build_MDRMDA();
    void build_Rel();
    void build_BA();
    void build_COM();

    void determine_Cover_Size_Range();
    bool do_Iteration_SEQ(size_t const m);

    bool is_Equivalent_FA(FA const& imda, int const method = 0) const;

	bool all_Loops_Present(FA const& scom, Subset const& s) const;
    bool loop_Present(Simple_Loop const& sl, FA const& scom, Subset const& s) const;

	void build_SubCOM(Subset const& s, FA& scom) const;
	void get_SubCOM_By_States(Subset const& s, FA& scom) const;
    
    void print_CM_TXT(std::ostream& os, Subset_Matrix const& cm) const;
    void print_CM_LaTeX(std::ostream& os, Subset_Matrix const& cm) const;
    void print_Rel_TXT(std::ostream& os) const;
    void print_Rel_LaTeX(std::ostream& os) const;
    void print_Grids_Set_TXT(std::ostream& os, Subset const& s) const;
    void print_Grids_Set_LaTeX(std::ostream& os, Subset const& s) const;

	std::string BA_State_To_String(u_t const id, Labels_Type const lt = TXT) const;
	void print_BA_TXT(std::ostream& os) const;
	void print_BA_Path_TXT(std::ostream& os, Path const& p) const;

	std::string subCOM_State_To_String(u_t const id, Subset const& s, Brackets_Type const bt = BRACES, Labels_Type const lt = TXT) const;
	void print_subCOM_TXT(std::ostream& os, FA const& scom, Subset const& s) const;
};

void CalcStatD(std::vector<COM_Statistics> const& vcoms, D_COM_Stat const& elem, double& min, double& max, double& mean, double& dev);
void CalcStatU(std::vector<COM_Statistics> const& vcoms, U_COM_Stat const& elem, u_t& min, u_t& max, double& mean, double& dev);
void CalcSumD(std::vector<COM_Statistics> const& vcoms, D_COM_Stat const& elem, double& sum);
void CalcSumU(std::vector<COM_Statistics> const& vcoms, U_COM_Stat const& elem, u_t& sum);
void CalcSumB(std::vector<COM_Statistics> const& vcoms, B_COM_Stat const& elem, u_t& sum);
void OutputStatD(std::ostream& os, std::string const& name, std::vector<COM_Statistics> const& vcoms, D_COM_Stat const& elem);
void OutputStatU(std::ostream& os, std::string const& name, std::vector<COM_Statistics> const& vcoms, U_COM_Stat const& elem);
void OutputSumD(std::ostream& os, std::string const& name, std::vector<COM_Statistics> const& vcoms, D_COM_Stat const& elem);
void OutputSumU(std::ostream& os, std::string const& name, std::vector<COM_Statistics> const& vcoms, U_COM_Stat const& elem);
void OutputSumB(std::ostream& os, std::string const& name, std::vector<COM_Statistics> const& vcoms, B_COM_Stat const& elem);
void ProcessCOMStatistics(std::ostream& os, std::vector<COM_Statistics> const& vcoms);
}

//EOF!
